#include "lcd_init.h"
#include "stdio.h"
#include <string.h>
// #include "app.h"

typedef void (*FunType)(void);
//**********************************write function begin********************************************
void wr_cmd_4spi_8bcs(uint8_t par)
{
    LCD_DCXLow();
    LCD_CSLow();

    LCD_SCLLow();
    if (par & 0x80)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x40)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x20)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x10)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x08)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x04)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x02)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x01)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_CSHigh();
    LCD_SCLLow();
    // LCD_DCXHigh();
    // HAL_Delay(5);
}
void wr_dat_4spi_8bcs(uint8_t par)
{
    LCD_DCXHigh();
    LCD_CSLow();

    LCD_SCLLow();
    if (par & 0x80)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x40)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x20)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x10)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x08)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x04)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x02)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x01)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_CSHigh();
    // LCD_DCXHigh();
    LCD_SCLLow();
    // HAL_Delay(1);
}
//**********************************read function begin********************************************
void Write(uint8_t dc, uint8_t par)
{
    if (dc == Command)
    {
        wr_cmd_4spi_8bcs(par);
    }
    else if (dc == Parameter)
    {
        wr_dat_4spi_8bcs(par);
    }
}

void HW_Reset(void)
{
    LCD_RSTHigh();
    HAL_Delay(120);
    LCD_RSTLow();
    HAL_Delay(120);
    LCD_RSTHigh();
    HAL_Delay(200);
}

void Delay(uint32_t ms)
{
    HAL_Delay(ms);
}

void initial(void)
{
    HW_Reset();

    Delay(120); // Delay 120ms

    Write(Command, 0x11); // Sleep out

    Delay(120); // Delay 120ms

    Write(Command, 0xB1);
    Write(Parameter, 0x05);
    Write(Parameter, 0x3A);
    Write(Parameter, 0x3A);

    Write(Command, 0xB2);
    Write(Parameter, 0x05);
    Write(Parameter, 0x3A);
    Write(Parameter, 0x3A);

    Write(Command, 0xB3);
    Write(Parameter, 0x05);
    Write(Parameter, 0x3A);
    Write(Parameter, 0x3A);
    Write(Parameter, 0x05);
    Write(Parameter, 0x3A);
    Write(Parameter, 0x3A);

    Write(Command, 0xB4); // Dot inversion
    Write(Parameter, 0x03);

    Write(Command, 0xC0);
    Write(Parameter, 0x44);
    Write(Parameter, 0x04);
    Write(Parameter, 0x04);

    Write(Command, 0xC1);
    Write(Parameter, 0xC0);

    Write(Command, 0xC2);
    Write(Parameter, 0x0D);
    Write(Parameter, 0x00);

    Write(Command, 0xC3);
    Write(Parameter, 0x8D);
    Write(Parameter, 0x6A);

    Write(Command, 0xC4);
    Write(Parameter, 0x8D);
    Write(Parameter, 0xEE);

    Write(Command, 0xC5);
    Write(Parameter, 0x14);

    Write(Command, 0xE0);
    Write(Parameter, 0x06);
    Write(Parameter, 0x1C);
    Write(Parameter, 0x16);
    Write(Parameter, 0x16);
    Write(Parameter, 0x36);
    Write(Parameter, 0x2F);
    Write(Parameter, 0x28);
    Write(Parameter, 0x2A);
    Write(Parameter, 0x27);
    Write(Parameter, 0x24);
    Write(Parameter, 0x2C);
    Write(Parameter, 0x35);
    Write(Parameter, 0x00);
    Write(Parameter, 0x03);
    Write(Parameter, 0x00);
    Write(Parameter, 0x10);

    Write(Command, 0xE1);
    Write(Parameter, 0x05);
    Write(Parameter, 0x1A);
    Write(Parameter, 0x0F);
    Write(Parameter, 0x0E);
    Write(Parameter, 0x2E);
    Write(Parameter, 0x2A);
    Write(Parameter, 0x24);
    Write(Parameter, 0x29);
    Write(Parameter, 0x29);
    Write(Parameter, 0x27);
    Write(Parameter, 0x2F);
    Write(Parameter, 0x3C);
    Write(Parameter, 0x00);
    Write(Parameter, 0x02);
    Write(Parameter, 0x02);
    Write(Parameter, 0x10);

    Write(Command, 0x35);
    Write(Parameter, 0x00);

    Write(Command, 0x3A); // 65k mode
    Write(Parameter, 0x06);

    Write(Command, 0x36);
    Write(Parameter, 0xC0);

    // Write(Command, 0x21);
    Write(Command, 0x29); // Display on

    Write(Command, 0x2C);
}

void C096LAB_Init(void)
{
    LCD_RSTHigh();
    HAL_Delay(120);
    LCD_RSTLow();
    HAL_Delay(120);
    LCD_RSTHigh();
    HAL_Delay(200);

    HAL_Delay(120); // HAL_Delay 120ms

    wr_cmd_4spi_8bcs(0x11); // Sleep out

    HAL_Delay(120); // HAL_Delay 120ms

    wr_cmd_4spi_8bcs(0xB1);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x3A);

    wr_cmd_4spi_8bcs(0xB2);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x3A);

    wr_cmd_4spi_8bcs(0xB3);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x3A);

    wr_cmd_4spi_8bcs(0xB4); // Dot inversion
    wr_dat_4spi_8bcs(0x03);

    wr_cmd_4spi_8bcs(0xC0);
    wr_dat_4spi_8bcs(0x44);
    wr_dat_4spi_8bcs(0x04);
    wr_dat_4spi_8bcs(0x04);

    wr_cmd_4spi_8bcs(0xC1);
    wr_dat_4spi_8bcs(0xC0);

    wr_cmd_4spi_8bcs(0xC2);
    wr_dat_4spi_8bcs(0x0D);
    wr_dat_4spi_8bcs(0x00);

    wr_cmd_4spi_8bcs(0xC3);
    wr_dat_4spi_8bcs(0x8D);
    wr_dat_4spi_8bcs(0x6A);

    wr_cmd_4spi_8bcs(0xC4);
    wr_dat_4spi_8bcs(0x8D);
    wr_dat_4spi_8bcs(0xEE);

    wr_cmd_4spi_8bcs(0xC5);
    wr_dat_4spi_8bcs(0x14);

    wr_cmd_4spi_8bcs(0xE0);
    wr_dat_4spi_8bcs(0x06);
    wr_dat_4spi_8bcs(0x1C);
    wr_dat_4spi_8bcs(0x16);
    wr_dat_4spi_8bcs(0x16);
    wr_dat_4spi_8bcs(0x36);
    wr_dat_4spi_8bcs(0x2F);
    wr_dat_4spi_8bcs(0x28);
    wr_dat_4spi_8bcs(0x2A);
    wr_dat_4spi_8bcs(0x27);
    wr_dat_4spi_8bcs(0x24);
    wr_dat_4spi_8bcs(0x2C);
    wr_dat_4spi_8bcs(0x35);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x03);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x10);

    wr_cmd_4spi_8bcs(0xE1);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x1A);
    wr_dat_4spi_8bcs(0x0F);
    wr_dat_4spi_8bcs(0x0E);
    wr_dat_4spi_8bcs(0x2E);
    wr_dat_4spi_8bcs(0x2A);
    wr_dat_4spi_8bcs(0x24);
    wr_dat_4spi_8bcs(0x29);
    wr_dat_4spi_8bcs(0x29);
    wr_dat_4spi_8bcs(0x27);
    wr_dat_4spi_8bcs(0x2F);
    wr_dat_4spi_8bcs(0x3C);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x02);
    wr_dat_4spi_8bcs(0x02);
    wr_dat_4spi_8bcs(0x10);

    wr_cmd_4spi_8bcs(0x35);
    wr_dat_4spi_8bcs(0x00);

    wr_cmd_4spi_8bcs(0x3A); // 65k mode
    wr_dat_4spi_8bcs(0x66);

    wr_cmd_4spi_8bcs(0x36);
    wr_dat_4spi_8bcs(0x00);

    wr_cmd_4spi_8bcs(0x29); // Display on

    wr_cmd_4spi_8bcs(0x2C);

    wr_cmd_4spi_8bcs(0x2A);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x00 + 2);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x7F + 2);
    wr_cmd_4spi_8bcs(0x2B);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x00 + 1);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x9F + 1);
}

void sda_in(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin = SPI1_MOSI_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(SPI1_MOSI_GPIO_Port, &GPIO_InitStruct);
}

void sda_out(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin = SPI1_MOSI_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(SPI1_MOSI_GPIO_Port, &GPIO_InitStruct);
}

uint16_t read_one(uint8_t reg)
{
    uint16_t re_val = 0;
    // uint16_t addr = reg;
    sda_out();
    // LCD_SCLLow();
    LCD_DCXLow();
    LCD_CSLow();
    for (uint8_t i = 0; i < 8; i++)
    {
        LCD_SCLLow();
        if (reg & 0x80)
        {
            LCD_SDAHigh();
        }
        else
        {
            LCD_SDALow();
        }
        reg = reg << 1;
        LCD_SCLHigh();
    }
    LCD_SCLLow();
    // HAL_Delay(10);
    // LCD_SCLHigh();
    sda_in();
    for (uint8_t i = 0; i < 8; i++)
    {
        LCD_SCLLow();
        re_val = re_val << 1;
        re_val = re_val + HAL_GPIO_ReadPin(SPI1_MOSI_GPIO_Port, SPI1_MOSI_Pin);
        LCD_SCLHigh();
    }
    LCD_CSHigh();
    LCD_SCLLow();

    // printf("reg %02x one data is %02x\n\r", addr, re_val);

    sda_out();

    return re_val;
}

void NVM_ID(void)
{
    uint16_t id_val = 0;
    id_val = read_one(0xDC);
    printf("read id is %02x\n\r", id_val);
    if (id_val != 0x4A)
    {
        printf("id is wrong");
        /**/
        printf("2.Initialize the non-programmed module by software\n\r");
        HW_Reset();
        initial();
        drawFile("2.bmp");
        /**/
        printf("4.Write the ID into driver IC\n\r");
        Write(Command, 0xD9);
        Write(Parameter, 0x00);
        Write(Command, 0xD2);
        Write(Parameter, 0x4A);
        /**/
        printf("5.Enable NVM mode\n\r");
        Write(Command, 0xF1);
        Write(Parameter, 0x44);
        HAL_Delay(100);
        /**/
        printf("6.Supply 7.5V to VPP pad\n\r");
        VPPHigh();
        HAL_Delay(100);
        /**/
        printf("7.Erase NVM\n\r");
        Write(Command, 0xDF);
        Write(Parameter, 0xC5);
        Write(Parameter, 0xA5);
        HAL_Delay(20);
        /**/
        printf("8.Program NVM\n\r");
        Write(Command, 0xDF);
        Write(Parameter, 0x3A);
        Write(Parameter, 0xA5);
        HAL_Delay(20);
        /**/
        printf("9.Remove 7.5V from VPP pad\n\r");
        VPPLow();
        HAL_Delay(50);
        /**/
        printf("10.Disable NVM mode\n\r");
        Write(Command, 0xF1);
        Write(Parameter, 0x04);
        /**/
        printf("11.Turn off VDD and VDDI, waiting for 200ms then and turn on again\n\r");
        HAL_GPIO_WritePin(CTRL_VCC_GPIO_Port, CTRL_VCC_Pin, GPIO_PIN_RESET);
        HAL_Delay(200);
        HAL_GPIO_WritePin(CTRL_VCC_GPIO_Port, CTRL_VCC_Pin, GPIO_PIN_SET);
        /**/
        printf("12.Execute normal display on sequence\n\r");
        HW_Reset();
        initial();
        id_val = read_one(0xDC);
        printf("read id is %02x\n\r", id_val);
        if (id_val != 0x4A)
        {
            printf("program fail\n\r");
            drawFile("9.bmp");
            while (1)
            {
                HAL_Delay(100);
            }
        }
        else
        {
            printf("program OK\n\r");
        }
    }
    else
    {
        printf("ID is correct,normal display\n\r");
    }
}